local DIY = require "packages.diy_utility.diy_utility"

local function fujuMove(idx)
  return "#rfenghou_3d9j__fujuswitch_move" .. idx
end

local fuju = fk.CreateSkill{
  name = "rfenghou_3d9j__fujuswitch",
  dynamic_desc = function(self, player)
    if player and DIY.getSwitchState(player, "rfenghou_3d9j__fujuswitch") ~= 0 then
      local state = DIY.getSwitchState(player, "rfenghou_3d9j__fujuswitch")
      return "rfenghou_3d9j__fujuswitch_dynamic:" .. Fk:translate("#rfenghou_3d9j__fujuswitch_type" .. state) .. ":" .. Fk:translate(fujuMove((state % 10) + 1))
    else
      return "rfenghou_3d9j__fujuswitch"
    end
  end
}

---@type table<integer, {filter: fun(p: ServerPlayer):(boolean), use: fun(player: ServerPlayer, to: ServerPlayer)}>
local fuju_table = {
  [1] = {
    filter = function(p)
      return #p:getCardIds("hej") ~= 0
    end,
    use = function(player, to)
      local room = player.room
      local alls = to:getCardIds("hej")
      if #alls == 0 then return false end
      local cards = room:askToCards(to, {
        min_num = 1,
        max_num = 1,
        include_equip = true,
        pattern = tostring(Exppattern:new{ id = alls }),
        expand_pile = to:getCardIds("j"),
        skill_name = fuju.name,
        prompt = "#rfenghou_3d9j__fujuswitch-askfor:::" .. fujuMove(1),
        cancelable = false
      })
      if #cards ~= 0 then
        room:moveCardTo(cards, Card.DiscardPile, nil, fk.ReasonPutIntoDiscardPile, fuju.name, nil, nil, player)
      end
    end
  },
  [2] = {
    filter = Util.TrueFunc,
    use = function(player, to)
      local room = player.room
      room:changeHp(to, -1, nil, fuju.name)
    end
  },
  [3] = {
    filter = function(p)
      return #p:getCardIds("h") ~= 0
    end,
    use = function(player, to)
      local room = player.room
      local alls = to:getCardIds("h")
      if #alls == 0 then return false end
      local cards = room:askToCards(to, {
        min_num = 1,
        max_num = 1,
        include_equip = false,
        pattern = tostring(Exppattern:new{ id = alls }),
        skill_name = fuju.name,
        prompt = "#rfenghou_3d9j__fujuswitch-askfor:::" .. fujuMove(3),
        cancelable = false
      })
      if #cards ~= 0 then
        room:moveCardTo(cards, Card.DiscardPile, nil, fk.ReasonPutIntoDiscardPile, fuju.name, nil, nil, player)
      end
    end
  },
  [4] = {
    filter = function(p)
      return p:getAttackRange() > 1
    end,
    use = function(player, to)
      local room = player.room
      room:addPlayerMark(to, "_rfenghou_3d9j__fujuswitch-minusatk")
    end
  },
  [5] = {
    filter = function(p)
      return p.maxHp >= 1
    end,
    use = function(player, to)
      local room = player.room
      room:changeMaxHp(to, -1)
    end
  },
  [6] = {
    filter = function(p)
      return #p:getCardIds("e") ~= 0
    end,
    use = function(player, to)
      local room = player.room
      local alls = to:getCardIds("e")
      if #alls == 0 then return false end
      local cards = room:askToCards(to, {
        min_num = 1,
        max_num = 1,
        include_equip = true,
        pattern = tostring(Exppattern:new{ id = alls }),
        skill_name = fuju.name,
        prompt = "#rfenghou_3d9j__fujuswitch-askfor:::" .. fujuMove(6),
        cancelable = false
      })
      if #cards ~= 0 then
        room:moveCardTo(cards, Card.DiscardPile, nil, fk.ReasonPutIntoDiscardPile, fuju.name, nil, nil, player)
      end
    end
  },
  [7] = {
    filter = function(p)
      return p:getMaxCards() > 1
    end,
    use = function(player, to)
      local room = player.room
      room:addPlayerMark(to, MarkEnum.MinusMaxCards)
    end
  },
  [8] = {
    filter = function(p)
      return #p:getAvailableEquipSlots() ~= 0
    end,
    use = function(player, to)
      local room = player.room
      local choices = to:getAvailableEquipSlots()
      if #choices == 0 then return false end
      local choice = room:askToChoice(to, {choices = choices, skill_name = fuju.name, prompt = "#rfenghou_3d9j__fujuswitch-askfor:::" .. fujuMove(8)})
      room:abortPlayerArea(to, choice)
    end
  },
  [9] = {
    filter = function(p)
      return #p:getCardIds("j") ~= 0
    end,
    use = function(player, to)
      local room = player.room
      local alls = to:getCardIds("j")
      if #alls == 0 then return false end
      local cards = room:askToCards(to, {
        min_num = 1,
        max_num = 1,
        include_equip = false,
        pattern = tostring(Exppattern:new{ id = alls }),
        expand_pile = alls,
        skill_name = fuju.name,
        prompt = "#rfenghou_3d9j__fujuswitch-askfor:::" .. fujuMove(9),
        cancelable = false
      })
      if #cards ~= 0 then
        room:moveCardTo(cards, Card.DiscardPile, nil, fk.ReasonPutIntoDiscardPile, fuju.name, nil, nil, player)
      end
    end
  },
  [10] = {
    filter = function(p)
    local skills = table.filter(p:getSkillNameList(), function(name)
      local skill = Fk.skills[name]
      return skill:isPlayerSkill(p) and not skill:hasTag(Skill.Compulsory)
    end)
    return #skills ~= 0
  end,
    use = function(player, to)
      local room = player.room
      local skills = table.filter(to:getSkillNameList(), function(name)
        local skill = Fk.skills[name]
        return skill:isPlayerSkill(to) and not skill:hasTag(Skill.Compulsory)
      end)
      if #skills == 0 then return false end
      local choice = room:askToCustomDialog(to, {
        skill_name = fuju.name,
        qml_path = "packages/utility/qml/ChooseSkillBox.qml",
        extra_data = { skills, 1, 1, "#rfenghou_3d9j__fujuswitch-askfor:::" .. fujuMove(10), {} },
      })
      if choice == "" then
        choice = table.random(skills)
      else
        choice = choice[1]
      end
      room:handleAddLoseSkills(to, "-" .. choice)
    end
  },
}

---神秘的过滤机器
---@param player ServerPlayer @ 技能拥有者
---@return ServerPlayer[]
local function fujuFilter(player)
  local room = player.room
  local targets = room:getAlivePlayers(false)
  return table.filter(targets, fuju_table[(DIY.getSwitchState(player, fuju.name) % 10) + 1].filter)
end

---神秘的消耗机器
---@type fun(self: TriggerSkill, event: TriggerEvent, target: ServerPlayer, player: ServerPlayer, data: TriggerData):boolean?
local function fujuOnCost(self, event, target, player, data)
  if table.contains(player:getTableMark("_rfenghou_3d9j__fujuswitch"), DIY.getSwitchState(player, fuju.name)) then return end
  local tos = player.room:askToChoosePlayers(player, {
    targets = fujuFilter(player),
    min_num = 1,
    max_num = 1,
    skill_name = fuju.name,
    prompt = "#rfenghou_3d9j__fujuswitch-invoke:::" .. fujuMove((DIY.getSwitchState(player, fuju.name) % 10) + 1)
  })
  if #tos ~= 0 then
    player.room:addTableMark(player, "_rfenghou_3d9j__fujuswitch", DIY.getSwitchState(player, fuju.name))
    event:setCostData(self, { tos = tos })
    return true
  end
end

---神秘的执行机器
---@type fun(self: TriggerSkill, event: TriggerEvent, target: ServerPlayer, player: ServerPlayer, data: TriggerData)
local function fujuOnUse(self, event, target, player, data)
  player.room:removeTableMark(player, "_rfenghou_3d9j__fujuswitch", DIY.getSwitchState(player, fuju.name))
  DIY.changeSwitchState(player, fuju.name)
  local tos = event:getCostData(self).tos
  if not tos or #tos == 0 then return end
  fuju_table[DIY.getSwitchState(player, fuju.name)].use(player, tos[1])
end

fuju:addAcquireEffect(function (self, player, is_start)
  DIY.setSwitchState(player, fuju.name, 1, 10)
end)
fuju:addLoseEffect(function (self, player, is_death)
  DIY.removeSwitchSkill(player, fuju.name)
end)

--偶遇神郭嘉
--体力的变更——体力值/体力上限变更后
fuju:addEffect(fk.HpChanged, {
  anim_type = "switch",
  can_trigger = function(self, event, target, player, data)
    return target == player and player:hasSkill(fuju.name) and DIY.getSwitchState(player, fuju.name) == 2
  end,
  on_cost = fujuOnCost,
  on_use = fujuOnUse
})
fuju:addEffect(fk.MaxHpChanged, {
  anim_type = "switch",
  can_trigger = function(self, event, target, player, data)
    return target == player and player:hasSkill(fuju.name) and DIY.getSwitchState(player, fuju.name) == 5
  end,
  on_cost = fujuOnCost,
  on_use = fujuOnUse
})
--装备栏数的变更——装备栏废除/恢复后
fuju:addEffect(fk.AreaAborted, {
  anim_type = "switch",
  can_trigger = function(self, event, target, player, data)
    return target == player and player:hasSkill(fuju.name) and DIY.getSwitchState(player, fuju.name) == 8
  end,
  on_cost = fujuOnCost,
  on_use = fujuOnUse
})
fuju:addEffect(fk.AreaResumed, {
  anim_type = "switch",
  can_trigger = function(self, event, target, player, data)
    return target == player and player:hasSkill(fuju.name) and DIY.getSwitchState(player, fuju.name) == 8
  end,
  on_cost = fujuOnCost,
  on_use = fujuOnUse
})
--非锁定技数的变更——获得/失去非锁定技后
fuju:addEffect(fk.EventAcquireSkill, {
  anim_type = "switch",
  can_trigger = function(self, event, target, player, data)
    if target == player and player:hasSkill(fuju.name) and DIY.getSwitchState(player, fuju.name) == 10 then
      return data.skill:isPlayerSkill(player) and not data.skill:hasTag(Skill.Compulsory)
    end
  end,
  on_cost = fujuOnCost,
  on_use = fujuOnUse
})
fuju:addEffect(fk.EventLoseSkill, {
  anim_type = "switch",
  can_trigger = function(self, event, target, player, data)
    if target == player and player:hasSkill(fuju.name) and DIY.getSwitchState(player, fuju.name) == 10 then
      return data.skill:isPlayerSkill(player) and not data.skill:hasTag(Skill.Compulsory)
    end
  end,
  on_cost = fujuOnCost,
  on_use = fujuOnUse
})

--小作文搭检测器
--牌数的变更——有牌移动后，若对应区域牌数与移动前记录不一致
--攻击范围——有牌变动后，若你的攻击范围和该时机前不一致；
fuju:addEffect(fk.BeforeCardsMove, {
  global = true,
  can_refresh = function(self, event, target, player, data)
    for _, move in ipairs(data) do
      if move.from == player or move.to == player then
        return true
      end
    end
  end,
  on_refresh = function(self, event, target, player, data)
    data.extra_data = data.extra_data or {}
    data.extra_data.rfenghou_3d9j__fujuRecord = data.extra_data.rfenghou_3d9j__fujuRecord or {}
    local ph, pe, pj = #player:getCardIds("h"), #player:getCardIds("e"), #player:getCardIds("j")
    data.extra_data.rfenghou_3d9j__fujuRecord[player] = {ph, pe, pj, ph + pe + pj, player:getMaxCards(), player:getAttackRange()}
  end
})
fuju:addEffect(fk.AfterCardsMove, {
  anim_type = "switch",
  can_trigger = function(self, event, target, player, data)
    if player:hasSkill(fuju.name) and data.extra_data and (data.extra_data.rfenghou_3d9j__fujuRecord or {})[player] then
      if DIY.getSwitchState(player, fuju.name) == 1 then
        return data.extra_data.rfenghou_3d9j__fujuRecord[player][4] ~= #player:getCardIds("hej")
      elseif DIY.getSwitchState(player, fuju.name) == 3 then
        return data.extra_data.rfenghou_3d9j__fujuRecord[player][1] ~= #player:getCardIds("h")
      elseif DIY.getSwitchState(player, fuju.name) == 4 then
        return data.extra_data.rfenghou_3d9j__fujuRecord[player][6] ~= player:getAttackRange()
      elseif DIY.getSwitchState(player, fuju.name) == 6 then
        return data.extra_data.rfenghou_3d9j__fujuRecord[player][2] ~= #player:getCardIds("e")
      elseif DIY.getSwitchState(player, fuju.name) == 8 then
        return data.extra_data.rfenghou_3d9j__fujuRecord[player][5] ~= player:getMaxCards()
      elseif DIY.getSwitchState(player, fuju.name) == 9 then
        return data.extra_data.rfenghou_3d9j__fujuRecord[player][3] ~= #player:getCardIds("j")
      end
    end
  end,
  on_cost = fujuOnCost,
  on_use = fujuOnUse
})

--耦合接耦合
--攻击范围/手牌上限/装备栏数——技能发动（所有技能）后，若你的攻击范围/手牌上限/装备栏数和该时机前不一致；
fuju:addEffect(fk.SkillEffect, {
  global = true,
  can_refresh = function(self, event, target, player, data)
    return player.seat == 1
  end,
  on_refresh = function(self, event, target, player, data)
    local room = player.room
    data.extra_data = data.extra_data or {}
    data.extra_data.rfenghou_3d9j__fujuRecord_Skill = data.extra_data.rfenghou_3d9j__fujuRecord_Skill or {}
    for _, p in ipairs(room.alive_players) do
      data.extra_data.rfenghou_3d9j__fujuRecord_Skill[p] = {p:getAttackRange(), p:getMaxCards(), #p.equipSlots}
    end
    -- local banner = room:getBanner("_rfenghou_3d9j__fujuRecord") or {}
    -- local idx = #banner + 1
    -- banner[idx] = {}
    -- for _, p in ipairs(room.alive_players) do
    --   banner[idx][p] = {p:getAttackRange(), p:getMaxCards(), #p.equipSlots}
    -- end
    -- if #banner > 2 then
    --   table.remove(banner, 1)
    -- end
    -- room:setBanner("_rfenghou_3d9j__fujuRecord", banner)
  end
})
fuju:addEffect(fk.AfterSkillEffect, {
  anim_type = "switch",
  can_trigger = function(self, event, target, player, data)
    local banner = (data.extra_data and data.extra_data.rfenghou_3d9j__fujuRecord_Skill)
    if player:hasSkill(fuju.name) and banner then
      if DIY.getSwitchState(player, fuju.name) == 4 then
        return banner[player][1] ~= player:getAttackRange()
      elseif DIY.getSwitchState(player, fuju.name) == 7 then
        return banner[player][2] ~= player:getMaxCards()
      elseif DIY.getSwitchState(player, fuju.name) == 8 then
        return banner[player][3] ~= #player.equipSlots
      end
    end
  end,
  on_cost = fujuOnCost,
  on_use = fujuOnUse
})
--最红温
--手牌上限——体力值变动后，若你的手牌上限和该时机前不一致；
fuju:addEffect(fk.BeforeHpChanged, {
  global = true,
  can_refresh = function(self, event, target, player, data)
    return target == player
  end,
  on_refresh = function(self, event, target, player, data)
    data.extra_data = data.extra_data or {}
    data.extra_data.rfenghou_3d9j__fujuRecord = data.extra_data.rfenghou_3d9j__fujuRecord or {}
    data.extra_data.rfenghou_3d9j__fujuRecord[player] = player:getMaxCards()
  end
})
fuju:addEffect(fk.HpChanged, {
  anim_type = "switch",
  can_trigger = function(self, event, target, player, data)
    if player:hasSkill(fuju.name) and data.extra_data and (data.extra_data.rfenghou_3d9j__fujuRecord or {})[player] then
      if DIY.getSwitchState(player, fuju.name) == 7 then
        return data.extra_data.rfenghou_3d9j__fujuRecord[player] ~= player:getMaxCards()
      end
    end
  end,
  on_cost = fujuOnCost,
  on_use = fujuOnUse
})
fuju:addEffect("atkrange", {
  correct_func = function(self, from, to)
    return -from:getMark("_rfenghou_3d9j__fujuswitch-minusatk")
  end
})

Fk:loadTranslationTable{
  [":rfenghou_3d9j__fujuswitch-info"] = "<br><br><font color='red'>请勿反馈包括重复询问发动在内的相关bug</font>",
}
Fk:loadTranslationTable{
  ["rfenghou_3d9j__fujuswitch"] = "拂局",
  [":rfenghou_3d9j__fujuswitch"] = "转换技，你当前状态对应的数值增加或减少后，你可以令一名角色将下一状态对应的内容减1：<br>" ..
  "①区域中牌②体力③手牌④攻击范围⑤体力上限⑥装备区牌⑦手牌上限⑧未废除装备栏⑨判定区牌⑩非锁定技。" .. Fk:translate(":rfenghou_3d9j__fujuswitch-info"),

  [":rfenghou_3d9j__fujuswitch_dynamic"] = "转换技，你的{1}增加或减少后，你可以令一名角色{2}。" .. Fk:translate(":rfenghou_3d9j__fujuswitch-info"),

  ["#rfenghou_3d9j__fujuswitch-invoke"] = "拂局：你可以令一名角色%arg",
  ["#rfenghou_3d9j__fujuswitch-askfor"] = "拂局：你须%arg",

  -- 神秘描述和神秘分支，此处只提供拼接服务
  ["#rfenghou_3d9j__fujuswitch_type1"] = "区域中牌数",
  ["#rfenghou_3d9j__fujuswitch_move1"] = "将区域内一张牌置入弃牌堆",
  ["#rfenghou_3d9j__fujuswitch_type2"] = "体力值",
  ["#rfenghou_3d9j__fujuswitch_move2"] = "减1点体力",
  ["#rfenghou_3d9j__fujuswitch_type3"] = "手牌数",
  ["#rfenghou_3d9j__fujuswitch_move3"] = "将一张手牌置入弃牌堆",
  ["#rfenghou_3d9j__fujuswitch_type4"] = "攻击范围",
  ["#rfenghou_3d9j__fujuswitch_move4"] = "攻击范围-1",
  ["#rfenghou_3d9j__fujuswitch_type5"] = "体力上限",
  ["#rfenghou_3d9j__fujuswitch_move5"] = "减1点体力上限",
  ["#rfenghou_3d9j__fujuswitch_type6"] = "装备区牌数",
  ["#rfenghou_3d9j__fujuswitch_move6"] = "将装备区一张牌置入弃牌堆",
  ["#rfenghou_3d9j__fujuswitch_type7"] = "手牌上限",
  ["#rfenghou_3d9j__fujuswitch_move7"] = "手牌上限-1",
  ["#rfenghou_3d9j__fujuswitch_type8"] = "未废除装备栏数",
  ["#rfenghou_3d9j__fujuswitch_move8"] = "废除一个装备栏",
  ["#rfenghou_3d9j__fujuswitch_type9"] = "判定区牌数",
  ["#rfenghou_3d9j__fujuswitch_move9"] = "将判定区一张牌置入弃牌堆",
  ["#rfenghou_3d9j__fujuswitch_type10"] = "非锁定技数",
  ["#rfenghou_3d9j__fujuswitch_move10"] = "失去一个非锁定技",
}

return fuju
